package de.g18.gruppe3.dataio.service.provider;

import java.util.HashMap;

import de.g18.gruppe3.common.io.FileExportService;
import de.g18.gruppe3.common.io.FileImportService;
import de.g18.gruppe3.common.io.SQLExportService;
import de.g18.gruppe3.common.io.SQLImportService;

/**
 * Stellt Methoden zu verfügung um auf die einzelnen Services der DatenIO-Schnittstelle zuzugreifen.
 * Die Klasse nutzt das Singelton-Pattern.
 *
 * @author <a href="mailto:kevinhuber.kh@gmail.com">Kevin Huber</a>
 */
public class DataIOServiceProvider {

    private static final String SERVICE_IMPLEMENTATION_PACKAGE = "de.g18.gruppe3.dataio.service.";

    private static DataIOServiceProvider instance;

    private final HashMap<Class<?>, Object> services;


    private DataIOServiceProvider() {
        services = new HashMap<Class<?>, Object>();
    }

    public static DataIOServiceProvider getInstance() {
        if (instance == null) {
            instance = createInstance();
        }
        return instance;
    }

    private static synchronized DataIOServiceProvider createInstance() {
        return new DataIOServiceProvider();
    }

    public FileImportService getCSVImportService() {
        return getService(FileImportService.class);
    }

    public FileExportService getCSVExportService() {
        return getService(FileExportService.class);
    }

    public SQLImportService getSQLImportService() {
        return getService(SQLImportService.class);
    }

    public SQLExportService getSQLExportService() {
        return getService(SQLExportService.class);
    }

    private <_Service extends Object> _Service getService(Class<_Service> aServiceClass) {
        _Service service = (_Service) services.get(aServiceClass);
        if (service == null) {
            service = createService(aServiceClass);
            services.put(aServiceClass, service);
        }
        return service;
    }

    private <_Service extends Object> _Service createService(Class<_Service> aServiceClass) {
        String className = SERVICE_IMPLEMENTATION_PACKAGE + aServiceClass.getSimpleName() + "Impl";
        Class serviceImplementation = null;
        try {
            serviceImplementation = Class.forName(className);
            return (_Service) serviceImplementation.newInstance();
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Can not find class '" + className + "'", e);
        } catch (InstantiationException e) {
            throw new IllegalStateException("Can not create new instance of class '" + className + "'", e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Can not access class '" + className + "'", e);
        }
    }
}
